package com.youlian.cloud.gateway.filter;

import com.dianping.cat.Cat;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.youlian.cloud.gateway.utils.DebugUtils;
import com.youlian.cloud.log.utils.CatMsgConstants;
import com.youlian.cloud.log.utils.EventProcessUtils;
import com.youlian.cloud.log.utils.RequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.apache.commons.io.IOUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;

/**
 * @author : liukx
 * @create : 2018/9/19 10:53
 * @email : liukx@elab-plus.com
 */
@Component
public class PostFilter extends ZuulFilter {

    private Logger logger = LoggerFactory.getLogger(PostFilter.class);

    @Autowired
    private ZuulProperties zuulProperties;

    private String ERROR_CODE = "CORE.ERROR.001";

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String responseBody = null;
        HttpServletRequest request = ctx.getRequest();
        StringBuilder filterExecutionSummary = ctx.getFilterExecutionSummary();
        if (ctx.getResponseDataStream() != null && DebugUtils.getValue(DebugUtils.OUT_RESPONSE)) {
            try {
                responseBody = IOUtils.toString(ctx.getResponseDataStream());
                ctx.setResponseBody(responseBody);
                HttpServletResponse response = ctx.getResponse();
                int statusCode = response.getStatus();
                if (!StringUtils.isEmpty(responseBody) && statusCode != HttpStatus.OK.value()) {
                    logger.info(" -------------- " + statusCode + " ---------CAT LogId >>>> " + Cat
                            .getCurrentMessageId());
                    logError(request, statusCode);
                    invokeDataPoint(ctx, false);
                } else {
                    invokeDataPoint(ctx, true);
                }
            } catch (IOException e) {
                logger.error("PostFilter Error ... ", e);
                e.printStackTrace();
            }
        }
        logger.info(" response : " + responseBody + " \n filter : " + filterExecutionSummary.toString());
        return null;
    }

    /**
     * 数据埋点
     *
     * @param ctx
     * @param result
     */
    private void invokeDataPoint(RequestContext ctx, boolean result) {
        Object serviceId = ctx.get("serviceId");
        if (!ObjectUtils.isEmpty(serviceId)) {
            if (result) {
                EventProcessUtils.write(CatMsgConstants.CONSUMER_CALL_SERVER, serviceId.toString());
            } else {
                EventProcessUtils.writeFail(CatMsgConstants.CONSUMER_CALL_SERVER, serviceId.toString());
            }
        }
    }

    /**
     * 记录异常请求信息
     *
     * @param request
     * @param statusCode
     */
    private void logError(HttpServletRequest request, int statusCode) {
        String clientIP = RequestUtils.getClientIP(request);
        String referer = RequestUtils.getReferer(request);
        String userAgent = RequestUtils.getUserAgent(request);
        String requestURI = request.getRequestURI();
        EventProcessUtils.write("error-clientIP", clientIP);
        EventProcessUtils.write("error-referer", referer);
        EventProcessUtils.write("error-userAgent", userAgent);
        EventProcessUtils.write(statusCode + "", requestURI);
    }

    @Override
    public boolean shouldFilter() {
        Set<String> ignoredPatterns = zuulProperties.getIgnoredPatterns();
        String requestURI = RequestContext.getCurrentContext().getRequest().getRequestURI();
        AntPathMatcher matcher = new AntPathMatcher("/");
        boolean match = false;
        for (String url : ignoredPatterns) {
            url = "/*" + url;
            match = matcher.match(url, requestURI);
            if (match) {
                break;
            }
        }
        return !match;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }


}
